package net.csiit.platform.codeguard.spring.classreading;

import net.csiit.platform.codeguard.classloader.CodeGuardConfiguration;
import net.csiit.platform.codeguard.tools.AES;
import net.csiit.platform.codeguard.util.StringUtils;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;

/**
 * @author adam
 * @date 2020/7/6
 */
public class DecryptResourceWrapper {

    public static Resource getResource(Resource resource) {
        try {
            URL url = resource.getURL();
            String className = getClassName(url);
            if (!StringUtils.isEmpty(className) && CodeGuardConfiguration.matches(className)) {
                return decryptResource(resource);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return resource;
    }

    private static String getClassName(URL url) {
        if (url == null) {
            return null;
        }

        String path = url.toString();
        if (!StringUtils.endsWith(path, ".class")) {
            return null;
        }

        path = StringUtils.replace(path, url.getProtocol(), "");
        path = StringUtils.replace(path, ".class", "");

        if (StringUtils.contains(path, "!")) {
            path = path.substring(path.lastIndexOf("!") + 1);
        }

        path = StringUtils.replace(path, "/", ".");
        if (StringUtils.startsWith(path, ".")) {
            path = path.substring(1);
        }

        return path;
    }

    private static Resource decryptResource(Resource original) throws IOException {
        try (InputStream inputStream = original.getInputStream();
             ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
            byte[] buffer = new byte[4096];
            int length = -1;
            while ((length = inputStream.read(buffer)) != -1) {
                byteArrayOutputStream.write(buffer, 0, length);
            }

            byte[] bytes = AES.decrypt(byteArrayOutputStream.toByteArray(), AES.pwdHandler(CodeGuardConfiguration.getKey()));
            if (bytes == null) {
                return original;
            }

            return new ByteArrayResource(bytes);
        }
    }
}
